[C#] Asp.net Mvc 使用 AntiForgery


Posted by mike-hsieh on 2023-12-14

在.net framework mvc 中,時常處理到 XSRF/CSRF 的資安問題,這邊記錄一下使用 axios + filter 的作法。

Step1: 新增一個Filter

public class GlobalAntiForgeryTokenFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        try
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("fail");
            }

            //  如果有AllowAnonymous要忽略驗證,就使用這一段
            object[] controllerAttributes = filterContext.Controller.GetType().GetCustomAttributes(true);
            object[] actionAttributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
            if (controllerAttributes.Any(p => p.ToString().Contains("AllowAnonymousAttribute")) ||
                actionAttributes.Any(p => p.ToString().Contains("AllowAnonymousAttribute")))
            {
                return;
            }

            //  驗證AntiForgeryToken
            var httpMethod = filterContext.HttpContext.Request.HttpMethod.ToUpper();
            if (httpMethod == "POST" && 
                filterContext.HttpContext.Request.IsAjaxRequest() == true)
            {
                var httpContext = filterContext.HttpContext;
                var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
                AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
            }

            //base.OnActionExecuting(filterContext);
        }
        catch (Exception)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { action = "Logout", controller = "Account" }));

            return;
        }

        base.OnActionExecuting(filterContext);
    }
}

Step2: 在FilterConfig中,註冊該Filter

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //  這邊加入自訂的驗證過濾器
            filters.Add(new GlobalAntiForgeryTokenFilter);
        }
    }

Step3: 在前端使用Antiforgery,並使用 axios 的 Post 方法

<body>

    <!-- 這邊加入 AntiForgeryToken -->
    @Html.AntiForgeryToken()

    <div>TODO...<div>

    <!-- 這邊加入 cdn axios -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    <script>
        //  取得AntiForgeryToken方法
        function getAntiForgeryToken() {
            var token = document.querySelector('input[name="__RequestVerificationToken"]').value;
            return token;
        }

        //  以下為Post
        axios.post(
            url,            //  'Home/GetData'
            data,           //  { id: 1 }
            {
                'withCredentials': true,
                'headers': {
                    'Content-Type': 'application/json;charset=UTF-8',
                    'X-Requested-With': 'XMLHttpRequest',   // For IsAjaxRequest()
                    __RequestVerificationToken: getAntiForgeryToken(),      //  這邊加入 AntiForgeryToken
                },
            },
        ).then(resp => {
            //  TODO...
        }).catch(err => {
            //  TODO...
        })
    </script>

</body>

#XSRF #csrf #AntiForgery #ASP.NET MVC #Axios #filter







Related Posts

第二周筆記 (JS) -1

第二周筆記 (JS) -1

接案平台分享

接案平台分享

Longitudinal Vehicle Model 實作小筆記

Longitudinal Vehicle Model 實作小筆記


Comments